package com.declum.archon.chunkserver.manager.disk.chunk;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class ChunkMetaLogger {
	List<String> available = new ArrayList<String>();
	List<String> markedforRemoval = new ArrayList<String>();
	private static final String ADD = "ADD ";
	private static final String REM = "REM ";
	String path;
	private FileWriter writter;
	private String metaFilePath;

	private ChunkMetaLogger(String path) {
		this.path = path;
	}

	public static ChunkMetaLogger getInstance(String path) throws IOException {
		ChunkMetaLogger logger = new ChunkMetaLogger(path);
		logger.openMetaFile();
		return logger;
	}

	private void openMetaFile() throws IOException {
		this.metaFilePath = this.path + File.separator + ".metalog";
		File metafile = new File(this.metaFilePath);
		if (metafile.exists()) {
			try {
				this.readMetaDataContent(metafile);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
		}
		this.writter = new FileWriter(metafile, true);
	}

	private void readMetaDataContent(File metafile) throws IOException {
		FileReader reader = new FileReader(metafile);
		BufferedReader buffReader = new BufferedReader(reader);
		String line, action, chunkid;
		while (true) {
			line = buffReader.readLine();
			if (line == null) {
				break;
			}
			action = line.substring(0, 4);
			chunkid = line.substring(4);
			if (action.equals(ChunkMetaLogger.ADD)) {
				if (!this.available.contains(chunkid)) {
					this.available.add(chunkid);
				}
			} else if (action.equals(ChunkMetaLogger.REM)) {
				if (!this.available.contains(chunkid)) {
					this.markedforRemoval.add(chunkid);
				}
				this.available.remove(chunkid);
			}
		}
		reader.close();
	}

	public synchronized void addChunkLog(String chunkID) throws IOException {
		synchronized (this) {
			if (!this.available.contains(chunkID)) {
				String log = ChunkMetaLogger.ADD + chunkID + "\r\n";
				this.available.add(chunkID);
				this.writter.append(log);
				this.writter.flush();
			}
		}
	}

	public synchronized void removeChunkLog(String chunkID) throws IOException {
		synchronized (this) {
			String log = ChunkMetaLogger.REM + chunkID + "\r\n";
			this.markedforRemoval.add(chunkID);
			this.available.remove(chunkID);
			this.writter.append(log);
		}
	}

	public void createSnapshot() {

	}

	public void syncWithLog() throws IOException {
		synchronized (this) {
			this.writter.close();
			this.writter = new FileWriter(this.metaFilePath);
			for (String data : this.available) {
				String log = ChunkMetaLogger.ADD + data + "\r\n";
				this.writter.append(log);
			}
			this.writter.close();
			this.writter = new FileWriter(this.metaFilePath, true);
		}
	}

	public void close() {
		try {
			this.syncWithLog();
			this.writter.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public String[] getAvailableChunks() {
		return this.available.toArray(new String[] {});
	}

	public String[] getChunksMarkedAsRemoval() {
		return this.markedforRemoval.toArray(new String[] {});
	}
}